package util;

import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.Calendar;
import java.util.Date;

/**
 * 日期工具类
 */
public class DateUtils {

    //默认时间格式
    public static final String DATE_TIME_STR = "yyyy-MM-dd HH:mm:ss";

    public static final String DATE_STR = "yyyy-MM-dd";
    public static final String DATE_STR_SHORT = "yyyy-M-d";
    public static final String ZHCN_DATE_STR = "yyyy年MM月dd日";
    public static final String ZHCN_DATE_TIME_STR = "yyyy年MM月dd日 HH时mm分ss秒";
    // 默认显示简体中文日期时间的格式
    public static final String ZHCN_DATATIMEF_STR_4yMMddHHmm = "yyyy-MM-dd HH时";

    //LocalDate -> Date
    public static Date asDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    //LocalDateTime -> Date
    public static Date asDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    //Date -> LocalDate
    public static LocalDate asLocalDate(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    //Date -> LocalDateTime
    public static LocalDateTime asLocalDateTime(Date date) {
        return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * 将小时数换算成返回以毫秒为单位的时间
     *
     * @param hours 小时
     */
    public static long getMicroSec(BigDecimal hours) {
        BigDecimal bd = hours.multiply(new BigDecimal(3600 * 1000));
        return bd.longValue();
    }

    /**
     * 返回几小时后的时间
     *
     * @param date  指定日期
     * @param hours 几小时
     * @return
     */
    public static Date addHours(Date date, Double hours) {
        long microSec = DateUtils.getMicroSec(BigDecimal.valueOf(hours));
        return new Date(date.getTime() + microSec);
    }

    /*
     * 获取两个日期对象相差的小时数
     */
    public static Double compareHours(Date dateBegin, Date dateEnd) {
        if (dateBegin == null || dateEnd == null) return null;
        double time1 = (double) dateBegin.getTime();
        double time2 = (double) dateEnd.getTime();
        double margin = time2 - time1;
//        BigDecimal days = new BigDecimal(margin / (1000 * 60 * 60));
        BigDecimal days = BigDecimal.valueOf(margin / (1000 * 60 * 60));
        return days.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /*
     *  获取两个日期对象相差的天数  24小时为一天
     */
    public static Double compareDay(Date dateBegin, Date dateEnd) {
        if (dateBegin == null || dateEnd == null) return null;
        double time1 = (double) dateBegin.getTime();
        double time2 = (double) dateEnd.getTime();
        double margin = time2 - time1;
//        BigDecimal days = new BigDecimal(margin / (1000 * 60 * 60 * 24));
        BigDecimal days = BigDecimal.valueOf(margin / (1000 * 60 * 60 * 24));
        return days.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 一个日期是另外一个日期之后的第多少天
     *
     * @param d1 第一个日期
     * @param d2 第二个日期
     * @return dt2 和 dt1 同一个日期 返回值 为 1
     */
    public static int afterDays(Date d1, Date d2) {
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime dt1 = LocalDateTime.ofInstant(d1.toInstant(), zoneId);
        LocalDateTime dt2 = LocalDateTime.ofInstant(d2.toInstant(), zoneId);
        return passedDays(dt1, dt2) + 1;
    }

    /**
     * 一个日期是另外一个日期之后的第多少天
     *
     * @param dt1 第一个日期
     * @param dt2 第二个日期
     * @return dt2 和 dt1 同一个日期 返回值 为 1
     */
    public static int afterDays(LocalDateTime dt1, LocalDateTime dt2) {
        return passedDays(dt1, dt2) + 1;
    }

    /**
     * 一个日期 到 另一个日期 过了多少天
     *
     * @param dt1 第一个时间点
     * @param dt2 第二个时间点
     * @return dt2 是 dt1 后面一个日期 返回值 为 1
     */
    public static int passedDays(LocalDateTime dt1, LocalDateTime dt2) {
        //获取第一个时间点的时间戳对应的秒数
        long t1 = dt1.toEpochSecond(ZoneOffset.ofHours(0));
        //获取第一个时间点在是1970年1月1日后的第几天
        long day1 = t1 / (60 * 60 * 24);
        //获取第二个时间点的时间戳对应的秒数
        long t2 = dt2.toEpochSecond(ZoneOffset.ofHours(0));
        //获取第二个时间点在是1970年1月1日后的第几天
        long day2 = t2 / (60 * 60 * 24);
        //返回两个时间点的天数差
        return (int) (day2 - day1);
    }


    /**
     * 指定格式的时间字符串 转化为日期
     *
     * @param date
     * @param format
     * @return
     */
    public static String dateToString(Date date, String format) {
        if (format == null) {
            format = ZHCN_DATATIMEF_STR_4yMMddHHmm;
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.format(date);
    }

    /**
     * 默认格式（"yyyy-MM-dd HH:mm:ss"）的字符串转化为 日期
     *
     * @param date
     * @return
     */
    public static Date parseDate(String date) {
        return DateUtils.StringToDate(date, DateUtils.DATE_TIME_STR);
    }

    /**
     * 获取当前日期yyyy年MM月dd日的形式
     */
    public static String getCurZhCNDate() {
        return dateToString(new Date(), ZHCN_DATATIMEF_STR_4yMMddHHmm);
    }

    /**
     * 字符串转日期类
     */
    public static Date StringToDate(String strDate, String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        Date date = null;
        try {
            date = simpleDateFormat.parse(strDate);
        } catch (ParseException e) {
            e.printStackTrace();
            date = new Date();
        }
        return date;
    }

    /**
     * 获得某天最小时间 2017-10-15 00:00:00
     *
     * @param date
     */
    public static Date getStartOfDay(Date date) {
        if (date != null) {
            LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
            LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
            return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
        } else {
            return date;
        }
    }

    /**
     * 获得某天最大时间 2017-10-15 23:59:59
     *
     * @param date
     */
    public static Date getEndOfDay(Date date) {
        if (date != null) {
            LocalDateTime localDateTime = LocalDateTime.ofInstant((Instant.ofEpochMilli(date.getTime())), ZoneId.systemDefault());
            LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
            return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
        } else {
            return date;
        }
    }

    /**
     * 指定天数后（前）的日期
     *
     * @param days
     * @return
     */
    public static Date getDateAddDays(int days) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, days);
        return cal.getTime();
    }

    public static String getTime(LocalDateTime currentTime, LocalDateTime firstTime) {
        return getTime(asDate(currentTime), asDate(firstTime));
    }

    //获取时间差方法
    public static String getTime(Date currentTime, Date firstTime) {
        long diff = currentTime.getTime() - firstTime.getTime();//这样得到的差值是微秒级别
        Calendar currentTimes = dataToCalendar(currentTime);//当前系统时间转Calendar类型
        Calendar firstTimes = dataToCalendar(firstTime);//查询的数据时间转Calendar类型
        int year = currentTimes.get(Calendar.YEAR) - firstTimes.get(Calendar.YEAR);//获取年
        int month = currentTimes.get(Calendar.MONTH) - firstTimes.get(Calendar.MONTH);
        int day = currentTimes.get(Calendar.DAY_OF_MONTH) - firstTimes.get(Calendar.DAY_OF_MONTH);
        if (day < 0) {
            month -= 1;
            currentTimes.add(Calendar.MONTH, -1);
            day = day + currentTimes.getActualMaximum(Calendar.DAY_OF_MONTH);//获取日
        }
        if (month < 0) {
            month = (month + 12) % 12;//获取月
            year--;
        }
        long days = diff / (1000 * 60 * 60 * 24);
        long hours = (diff - days * (1000 * 60 * 60 * 24)) / (1000 * 60 * 60); //获取时 
        long minutes = (diff - days * (1000 * 60 * 60 * 24) - hours * (1000 * 60 * 60)) / (1000 * 60);//获取分钟
        long s = (diff / 1000 - days * 24 * 60 * 60 - hours * 60 * 60 - minutes * 60);//获取秒
        //年月日时分秒
        String duration = StringUtils.EMPTY;
        if (year > 0) {
            duration += year + "年";
        }
        if (!StringUtils.isEmpty(duration) || month > 0) {
            duration += month + "月";
        }
        if (!StringUtils.isEmpty(duration) || day > 0) {
            duration += day + "日";
        }
        if (!StringUtils.isEmpty(duration) || hours > 0) {
            duration += hours + "时";
        }
        if (!StringUtils.isEmpty(duration) || minutes > 0) {
            duration += minutes + "分";
        }
        if (!StringUtils.isEmpty(duration) || s > 0) {
            duration += s + "秒";
        }
        return duration;
    }

    //Date类型转Calendar类型
    public static Calendar dataToCalendar(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar;
    }

    public static void main(String[] args) {
        LocalDateTime of1 = LocalDateTime.parse("2021-07-06T01:01:00");
        LocalDateTime of2 = LocalDateTime.parse("2021-07-06T01:02:00");
        System.out.println(afterDays(of1, of2));//1
        System.out.println(afterDays(Date.from(of1.atZone(ZoneId.systemDefault()).toInstant()), Date.from(of2.atZone(ZoneId.systemDefault()).toInstant())));//1

        System.out.println("===============");

        LocalDateTime of3 = LocalDateTime.parse("2021-07-06T21:01:00");
        LocalDateTime of4 = LocalDateTime.parse("2021-07-07T01:02:00");
        System.out.println(afterDays(of3, of4));//2
        System.out.println(afterDays(Date.from(of3.atZone(ZoneId.systemDefault()).toInstant()), Date.from(of4.atZone(ZoneId.systemDefault()).toInstant())));//1

        System.out.println("===============");

        LocalDateTime of5 = LocalDateTime.parse("2021-07-06T01:01:00");
        LocalDateTime of6 = LocalDateTime.parse("2021-07-07T21:02:00");
        System.out.println(afterDays(of5, of6));//2
        System.out.println(afterDays(Date.from(of5.atZone(ZoneId.systemDefault()).toInstant()), Date.from(of6.atZone(ZoneId.systemDefault()).toInstant())));//1
    }


}
